// compile: g++ -o shared_ptr shared_ptr.cc -std=c++11
// run: ./shared_ptr
#include <iostream>
#include <memory>
#include <string>
using namespace std;
class XXX : public enable_shared_from_this<XXX> {
 public:
  XXX() {
    ptr = new int(10);
    cout << "constructed!" << endl;
  }
  XXX(const string& str) : str_(str) { XXX(); }
  std::shared_ptr<XXX> Getptr() {
    return shared_from_this();
    // return shared_ptr<XXX>(this);  // 错误，导致double free
  }
  ~XXX() { cout << "deconstructed!" << endl; }

 private:
  string str_;
  int* ptr;
};
// 基本使用:构造智能指针、use_count、get
void Func(shared_ptr<XXX> sp) {
  cout << "sp.use_count() = " << sp.use_count() << endl;
}
void Test1() {
  shared_ptr<XXX> sp1(new XXX());  // 传递原生指针
  string s = "name2";
  shared_ptr<XXX> sp2 = make_shared<XXX>(s);  // make_shared方式
  shared_ptr<XXX> sp3 = sp2;                  // 拷贝构造
  cout << "sp1.use_count() = " << sp1.use_count() << endl;
  cout << "sp2.use_count() = " << sp2.use_count() << endl;
  cout << "sp3.use_count() = " << sp3.use_count() << endl;

  Func(sp2);  // 将智能指针作为参数传递

  cout << "sp1.use_count() = " << sp1.use_count() << endl;
  cout << "sp2.use_count() = " << sp2.use_count() << endl;
  cout << "sp3.use_count() = " << sp3.use_count() << endl;

  XXX* tmp_ptr = sp1.get();  // 获取裸指针，不影响引用计数

  cout << "sp1.use_count() = " << sp1.use_count() << endl;
  cout << "sp2.use_count() = " << sp2.use_count() << endl;
  cout << "sp3.use_count() = " << sp3.use_count() << endl;
}

// shared_ptr自定义删除器(可调用对象)，比如关闭文件描述符、数据库连接
// 默认删除器：std::shared_ptr<T> ptr(new T,[](T* p) {delete p;});
void Test2() {
  std::shared_ptr<int> ptr1(new int[5], [](int* p) {
    delete[] p;
    cout << "资源释放完毕" << endl;
  });
  std::shared_ptr<int> ptr2(new int[4], std::default_delete<int[]>());
  std::shared_ptr<XXX> ptr3(new XXX[4], std::default_delete<XXX[]>());
}
// reset使用
void Test3() {}
// 使用enable_shared_from_this 和 share_from_this
void Test4() {
  shared_ptr<XXX> sp1 = make_shared<XXX>();
  shared_ptr<XXX> sp2 = sp1->Getptr();
  // XXX x;
  // auto sp3 = x.Getptr(); 错误，因为没有使用shared_ptr包含对象
}
// 循环引用问题
void Test5() {}
int main() {
  // Test1();
  Test2();
  // Test3();
  // Test4();
  // Test5();
  return 0;
}
// shared_ptr对象构造、拷贝，引用计数加一
// shared_ptr对象销毁 ，引用计数减一